package api

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/chromedp/cdproto/browser"
	"github.com/chromedp/chromedp"
	"github.com/wallace5303/ee-go/ehelper"
	"github.com/wallace5303/ee-go/ehttp/router"
	"github.com/wallace5303/ee-go/elog"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"time"
)

func StartBrowser(c *router.Ctx) {
	ret := ehelper.GetJson()
	defer c.JSON(ret)
	//解析json
	bt, err := c.GinCtx.GetRawData()
	if err != nil {
		elog.Logger.Error(err.Error())
		ret.Data = "获取参数失败"
		return
	}
	param := ChromeDPParameter{}
	errJson := json.Unmarshal(bt, &param)
	if errJson != nil {
		elog.Logger.Error(errJson.Error())
		ret.Data = "获取参数失败"
		return
	}
	//异步执行
	go StartByParameter(param)
	ret.Data = "数据抓取已启动"
	elog.Logger.Info(param)
}

type ChromeDPParameter struct {
	LoadAddress LoadAddress `json:"loadAddress"`
	Steps       []Step      `json:"steps"`
	UseCache    []bool      `json:"useCache" desc:"使用使用cache缓存"`
}

type LoadAddress struct {
	Protocol string `json:"protocol"`
	Url      string `json:"url"`
}

type Step struct {
	//步骤
	Key int8 `json:"key" desc:"步骤"`
	//类型：1:输入框、2:时间选择器、3:按钮,4:等待元素加载
	Type string `json:"type"`
	//地址
	Path string `json:"path"`
	//选择器地址类型： 1-xpath,2-JS选择器
	PathType string `json:"pathType"`
	//输入框输入的值
	Value string `json:"value"`
	//等待时间
	WaitTime int8 `json:"waitTime"`
}

// StartByParameter 发起请求
func StartByParameter(param ChromeDPParameter) {
	ctx, cancel := chromedp.NewExecAllocator(
		context.Background(),

		// 以默认配置的数组为基础，覆写headless参数
		// 当然也可以根据自己的需要进行修改，这个flag是浏览器的设置
		append(
			chromedp.DefaultExecAllocatorOptions[:],
			chromedp.Flag("headless", false),
		)...,
	)
	defer cancel()
	// 创建新的chromedp上下文对象，超时时间的设置不分先后
	ctx, cancel = context.WithTimeout(ctx, 30*time.Second)
	defer cancel()
	ctx, cancel = chromedp.NewContext(
		ctx,
		// 设置日志方法
		chromedp.WithLogf(log.Printf),
	)
	defer cancel()
	var buf []byte
	var err error
	wd, err := os.Getwd()
	if err != nil {
		elog.Logger.Fatal(err)
	}
	done := make(chan string, 1)
	//监听下载完成
	chromedp.ListenTarget(ctx, func(v interface{}) {
		if ev, ok := v.(*browser.EventDownloadProgress); ok {
			completed := "(unknown)"
			if ev.TotalBytes != 0 {
				completed = fmt.Sprintf("%0.2f%%", ev.ReceivedBytes/ev.TotalBytes*100.0)
			}
			elog.Logger.Info("state: %s, completed: %s\n", ev.State.String(), completed)
			if ev.State == browser.DownloadProgressStateCompleted {
				done <- ev.GUID
				close(done)
			}
		}
	})

	var actions = make([]chromedp.Action, 0)
	actions = append(actions, chromedp.Navigate(param.LoadAddress.Url))

	for i := range param.Steps {
		item := param.Steps[i]
		fmt.Println("本次执行数据：", item.Path)
		if item.Type == `1` {
			//输入框
			switch item.PathType {
			case `1`:
				{
					fmt.Println("sendKeyBySearch:key=", item.Path, ",value=", item.Value)
					actions = append(actions, chromedp.SendKeys(item.Path, item.Value, chromedp.BySearch))
				}
			case `2`:
				{
					fmt.Println("sendKeyByJSPath:key=", item.Path, ",value=", item.Value)
					actions = append(actions, chromedp.SendKeys(item.Path, item.Value, chromedp.ByJSPath))
				}
			}
		} else if item.Type == `2` {
			//2、时间选择器
			switch item.PathType {
			case `1`:
				{
					actions = append(actions, chromedp.SendKeys(item.Path, item.Value, chromedp.BySearch))
				}
			case `2`:
				{
					actions = append(actions, chromedp.SendKeys(item.Path, item.Value, chromedp.ByJSPath))
				}
			}
		} else if item.Type == `3` {
			//3、按钮
			switch item.PathType {
			case `1`:
				{
					actions = append(actions, chromedp.Click(item.Path, chromedp.BySearch))
				}
			case `2`:
				{
					actions = append(actions, chromedp.Click(item.Path, chromedp.ByJSPath))
				}
			}
		} else if item.Type == `4` {
			//3、按钮
			switch item.PathType {
			case `1`:
				{
					actions = append(actions, chromedp.WaitVisible(item.Path, chromedp.BySearch))
				}
			case `2`:
				{
					actions = append(actions, chromedp.WaitVisible(item.Path, chromedp.ByJSPath))
				}
			}
		}
		if item.WaitTime > 0 {
			actions = append(actions, chromedp.Sleep(time.Duration(item.WaitTime)*time.Second))
		}
	}

	// 执行我们自定义的任务
	if err := chromedp.Run(ctx,
		actions...,
	); err != nil {
		elog.Logger.Fatal(err)
		return
	}

	//监听下载完成
	guid := <-done
	// We can predict the exact file location and name here because of how we
	// configured SetDownloadBehavior and WithDownloadPath
	log.Printf("wrote %s", filepath.Join(wd, guid))
	chromedp.Stop()
	if err != nil {
		elog.Logger.Fatal(err)
	}
	if err := ioutil.WriteFile("1.png", buf, 0644); err != nil {
		elog.Logger.Fatal(err)
	}
}
